#!/usr/bin/env python3

"""
build ctsm library
"""
import sys, os

_CIMEROOT = os.environ.get("CIMEROOT")
if _CIMEROOT is None:
    raise SystemExit("ERROR: must set CIMEROOT environment variable")

_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools")
sys.path.append(_LIBDIR)

from standard_script_setup import *
from CIME.buildlib import parse_input
from CIME.build import get_standard_makefile_args
from CIME.case import Case
from CIME.utils import run_cmd, expect

logger = logging.getLogger(__name__)


###############################################################################
def _write_ctsm_mk(gmake, gmake_opts, makefile, exeroot, libroot):
    """Writes a ctsm.mk file in exeroot.

    This file can be included by atmosphere model builds outside of cime.
    """

    cime_output_file = os.path.join(exeroot, "cime_variables.mk")
    # Set COMP_NAME=driver because some link flags are set differently when COMP_NAME=driver, and
    # those are the ones we want here.
    cmd = (
        "{gmake} write_include_and_link_flags OUTPUT_FILE={cime_output_file} "
        "COMP_NAME=driver {gmake_opts} -f {makefile} "
    ).format(
        gmake=gmake,
        cime_output_file=cime_output_file,
        gmake_opts=gmake_opts,
        makefile=makefile,
    )
    rc, out, err = run_cmd(cmd)
    logger.info("%s: \n\n output:\n %s \n\n err:\n\n%s\n" % (cmd, out, err))
    expect(rc == 0, "Command %s failed with rc=%s" % (cmd, rc))

    ctsm_mk_path = os.path.join(exeroot, "ctsm.mk")
    with open(ctsm_mk_path, "w") as ctsm_mk:
        ctsm_mk.write(
            """
# ======================================================================
# Include this file to get makefile variables needed to include / link
# LILAC/CTSM in an atmosphere model's build
#
# Variables of interest are:
# - CTSM_INCLUDES: add this to the compilation line
# - CTSM_LIBS: add this to the link line
# ======================================================================

# ======================================================================
# The following CIME variables are meant for internal use, and generally
# should not be included directly in an atmosphere model's build.
# ======================================================================

"""
        )
        with open(cime_output_file) as infile:
            ctsm_mk.write(infile.read())

    ctsm_bld_dir = os.path.abspath(os.path.join(libroot, os.pardir))
    with open(ctsm_mk_path, "a") as ctsm_mk:
        ctsm_mk.write(
            """
# ======================================================================
# The following settings are meant for internal use, and generally
# should not be included directly in an atmosphere model's build.
# NOTE: clm library name and subdirectory will eventually need to
#       be updated to ctsm.
# ======================================================================

CTSM_BLD_DIR   = {ctsm_bld_dir}
CTSM_INC       = $(CTSM_BLD_DIR)/clm/obj

# ======================================================================
# The following settings should be included in an atmosphere model's build.
# ======================================================================

CTSM_INCLUDES = $(CIME_ESMF_F90COMPILEPATHS) -I$(CIME_CSM_SHR_INCLUDE) -I$(CTSM_INC)
CTSM_LIBS = -L$(CTSM_BLD_DIR)/lib -lclm $(CIME_ULIBS) $(CIME_SLIBS) $(CIME_MLIBS) $(CIME_F90_LDFLAGS)
""".format(
                ctsm_bld_dir=ctsm_bld_dir
            )
        )


###############################################################################
def _main_func():
    ###############################################################################

    caseroot, libroot, bldroot = parse_input(sys.argv)

    with Case(caseroot) as case:

        casetools = case.get_value("CASETOOLS")
        makefile = os.path.join(casetools, "Makefile")
        lnd_root = case.get_value("COMP_ROOT_DIR_LND")
        gmake_j = case.get_value("GMAKE_J")
        gmake = case.get_value("GMAKE")
        gmake_opts = get_standard_makefile_args(case)
        driver = case.get_value("COMP_INTERFACE").lower()
        lilac_mode = case.get_value("LILAC_MODE")

        if lilac_mode == "on":
            driver = "lilac"

        # -------------------------------------------------------
        # create Filepath file
        # -------------------------------------------------------
        compname = case.get_value("COMP_LND")
        filepath_file = os.path.join(bldroot, "Filepath")
        if not os.path.isfile(filepath_file):
            caseroot = case.get_value("CASEROOT")
            expect(
                ((compname == "clm") or (compname == "ctsm")),
                "Unexpected COMP_LND name: %s" % (compname),
            )

            paths = [
                os.path.join(caseroot, "SourceMods", "src." + compname),
                os.path.join(lnd_root, "src", "cpl", driver),
                os.path.join(lnd_root, "src", "main"),
                os.path.join(lnd_root, "src", "biogeophys"),
                os.path.join(lnd_root, "src", "biogeochem"),
                os.path.join(lnd_root, "src", "soilbiogeochem"),
                os.path.join(lnd_root, "src", "dyn_subgrid"),
                os.path.join(lnd_root, "src", "init_interp"),
                os.path.join(lnd_root, "src", "self_tests"),
                os.path.join(lnd_root, "src", "fates"),
                os.path.join(lnd_root, "src", "fates", "main"),
                os.path.join(lnd_root, "src", "fates", "biogeophys"),
                os.path.join(lnd_root, "src", "fates", "biogeochem"),
                os.path.join(lnd_root, "src", "fates", "fire"),
                os.path.join(lnd_root, "src", "fates", "parteh"),
                os.path.join(lnd_root, "src", "fates", "radiation"),
                os.path.join(lnd_root, "src", "utils"),
                os.path.join(lnd_root, "src", "cpl"),
                os.path.join(lnd_root, "src", "cpl", "utils"),
            ]

            if lilac_mode == "on":
                paths.append(os.path.join(lnd_root, "lilac", "src"))
                # If we want to build with a real river model (e.g., MOSART), we'll need
                # to use its directories in place of stub_rof
                paths.append(os.path.join(lnd_root, "lilac", "stub_rof"))

            if driver == "lilac" or driver == "nuopc":
                paths.append(os.path.join(lnd_root, "src", "cpl", "share_esmf"))

            with open(filepath_file, "w") as filepath:
                filepath.write("\n".join(paths))
                filepath.write("\n")

        # -------------------------------------------------------
        # create the library in libroot
        # -------------------------------------------------------

        complib = os.path.join(libroot, "lib%s.a" % (compname))

        cmd = "{} complib -j {} COMP_NAME={} COMPLIB={} -f {} {}".format(
            gmake, gmake_j, compname, complib, makefile, gmake_opts
        )

        rc, out, err = run_cmd(cmd)
        logger.info("%s: \n\n output:\n %s \n\n err:\n\n%s\n" % (cmd, out, err))
        expect(rc == 0, "Command %s failed with rc=%s" % (cmd, rc))

        # ------------------------------------------------------------------------
        # for lilac usage, we need a file containing some Makefile variables (for the atmosphere model's build)
        # ------------------------------------------------------------------------

        if lilac_mode == "on":
            _write_ctsm_mk(
                gmake=gmake,
                gmake_opts=gmake_opts,
                makefile=makefile,
                exeroot=case.get_value("EXEROOT"),
                libroot=libroot,
            )


###############################################################################

if __name__ == "__main__":
    logger.warning(
        "WARNING: buildlib is being called as a program rather than a subroutine as "
        + "it is expected to be in the CESM context"
    )
    _main_func()
